package cn.infozr.api.client;

import java.text.SimpleDateFormat;
import java.util.*;

import cn.infozr.api.util.MD5Util;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.annotation.JsonInclude;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * 药品出库信息上传接口客户端
 * 用于测试 https://IP:端口/ygydapi/v1/uploadDrugOut 接口
 */
public class DrugOutUploadApiClient extends BaseClient {
    

    
    /**
     * 药品出库信息数据项
     */
    public static class DrugOutItem {
        private String ypwybsm;      // 药品唯一标识码
        private String yppzwh;  // 完整的药品批准文号
        private String crklx;        // 出库类型：6销售出库 7损耗出库 8召回出库
        private String crksj;        // 出库时间 yyyy-MM-dd HH:mm:ss
//        private String jbr;          // 经办人姓名
        private String scrq;         // 生产日期格式 yyyy-MM-dd
        private String cpph;         // 产品批号
        private String yxqz;         // 有效期至格式 yyyy-MM-dd
        private Double sl;           // 药品数量，按最小计价包装单位统计，保留2位小数
        private Double dj;           // 医保支付价格，保留2位小数,如不传入则默认为0
        private Double xsdj;           // 药品销售价格，保留2位小数,如不传入则默认为0
        private String ypzsm;        // 20位的药品追溯码，多个之间用英文逗号隔开
        private String gmryzjlx;     // 购买人员证件类型,特殊药品销售必填
        private String gmryzjhm;     // 购买人员证件号码,特殊药品销售必填
        private String gmryxm;       // 购买人员姓名,特殊药品销售必填
        private Integer xsqd;        // 药品销售渠道 1线下 2线上
        private String xsxspt;       // 线上时必填，线上销售平台名称
        private String bz;           // 备注
        
        // Getters and Setters
        public String getYpwybsm() { return ypwybsm; }
        public void setYpwybsm(String ypwybsm) { this.ypwybsm = ypwybsm; }

        public String getYppzwh() {
            return yppzwh;
        }

        public void setYppzwh(String yppzwh) {
            this.yppzwh = yppzwh;
        }

        public String getCrklx() { return crklx; }
        public void setCrklx(String crklx) { this.crklx = crklx; }
        
        public String getCrksj() { return crksj; }
        public void setCrksj(String crksj) { this.crksj = crksj; }
        
//        public String getJbr() { return jbr; }
//        public void setJbr(String jbr) { this.jbr = jbr; }
        
        public String getScrq() { return scrq; }
        public void setScrq(String scrq) { this.scrq = scrq; }
        
        public String getCpph() { return cpph; }
        public void setCpph(String cpph) { this.cpph = cpph; }
        
        public String getYxqz() { return yxqz; }
        public void setYxqz(String yxqz) { this.yxqz = yxqz; }
        
        public Double getSl() { return sl; }
        public void setSl(Double sl) { this.sl = sl; }
        
        public Double getDj() { return dj; }
        public void setDj(Double dj) { this.dj = dj; }

        public Double getXsdj() { return xsdj; }
        public void setXsdj(Double xsdj) { this.xsdj = xsdj; }
        
        public String getYpzsm() { return ypzsm; }
        public void setYpzsm(String ypzsm) { this.ypzsm = ypzsm; }
        
        public String getGmryzjlx() { return gmryzjlx; }
        public void setGmryzjlx(String gmryzjlx) { this.gmryzjlx = gmryzjlx; }
        
        public String getGmryzjhm() { return gmryzjhm; }
        public void setGmryzjhm(String gmryzjhm) { this.gmryzjhm = gmryzjhm; }
        
        public String getGmryxm() { return gmryxm; }
        public void setGmryxm(String gmryxm) { this.gmryxm = gmryxm; }
        
        public Integer getXsqd() { return xsqd; }
        public void setXsqd(Integer xsqd) { this.xsqd = xsqd; }
        
        public String getXsxspt() { return xsxspt; }
        public void setXsxspt(String xsxspt) { this.xsxspt = xsxspt; }
        
        public String getBz() { return bz; }
        public void setBz(String bz) { this.bz = bz; }
    }
    
    /**
     * 药品出库信息上传请求参数类
     */
    public static class DrugOutUploadRequest {
        private String appId;
        private String timestamp;
        private String reqId;
        private String uscc;
        private String data;
        private String sign;
        
        // 构造函数
        public DrugOutUploadRequest() {
            this.timestamp = String.valueOf(System.currentTimeMillis());
        }
        
        // Getters and Setters
        public String getAppId() { return appId; }
        public void setAppId(String appId) { this.appId = appId; }
        
        public String getTimestamp() { return timestamp; }
        public void setTimestamp(String timestamp) { this.timestamp = timestamp; }
        
        public String getReqId() { return reqId; }
        public void setReqId(String reqId) { this.reqId = reqId; }
        
        public String getUscc() { return uscc; }
        public void setUscc(String uscc) { this.uscc = uscc; }
        
        public String getData() { return data; }
        public void setData(String data) { this.data = data; }
        
        public String getSign() { return sign; }
        public void setSign(String sign) { this.sign = sign; }
    }
    
    /**
     * 生成数据签名
     * @param request 请求参数对象
     * @return 签名字符串
     * @throws Exception 加密异常
     */
    protected String generateSign(DrugOutUploadRequest request) throws Exception {
        // 按照字段名的字典序拼接参数
        TreeMap<String, String> params = new TreeMap<>();
        params.put("appId", request.getAppId());
        params.put("reqId", request.getReqId());
        params.put("timestamp", request.getTimestamp());
        
        if (request.getUscc() != null && !request.getUscc().isEmpty()) {
            params.put("uscc", request.getUscc());
        }
        if (request.getData() != null && !request.getData().isEmpty()) {
            params.put("data", request.getData());
        }
        
        // 添加data参数到签名中（如果存在）
//        if (request.getData() != null && !request.getData().isEmpty()) {
//            ObjectMapper objectMapper = new ObjectMapper();
//            objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
//            String dataJson = objectMapper.writeValueAsString(request.getData());
//            params.put("data", dataJson);
//        }
        
        return cn.infozr.api.util.SM3SignatureUtil.generateSignature(params, SECRET_KEY);
    }
    
    /**
     * 调用药品出库信息上传接口
     * @param uscc 药店18位统一社会信用代码
     * @param data 药品出库信息数据列表
     * @return 接口响应结果
     * @throws Exception 网络或解析异常
     */
    public String uploadDrugOut(String uscc, List<DrugOutItem> data) throws Exception {
        // 构造请求参数
        DrugOutUploadRequest request = new DrugOutUploadRequest();
        request.setAppId(APP_ID);
        request.setTimestamp(String.valueOf(System.currentTimeMillis()));
        request.setUscc(uscc);
        if (data != null) {
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
            String dataJson = objectMapper.writeValueAsString(data);
            request.setData(dataJson);
            // 传递相同的reqId到服务器，服务器会忽略本次请求 （为防止网格中断导致数据重复上传,建议该值传MD5(数据)）
            String reqId = MD5Util.getMD5(dataJson);
            request.setReqId(reqId);
        }
        
        // 生成签名
        request.setSign(generateSign(request));
        
        // 发送POST请求
        return sendPostRequest(DRUG_OUT_API_URL, request);
    }
    
    /**
     * 发送POST请求
     * @param url 请求地址
     * @param request 请求参数对象
     * @return 响应结果
     * @throws Exception 网络异常
     */
    protected String sendPostRequest(String url, DrugOutUploadRequest request) throws Exception {
        URL obj = new URL(url);
        HttpURLConnection con = (HttpURLConnection) obj.openConnection();

        // 设置请求方法和请求头
        con.setRequestMethod("POST");
        con.setRequestProperty("Content-Type", "application/json; utf-8");
        con.setRequestProperty("Accept", "application/json");
        con.setDoOutput(true);

        // 序列化请求参数，过滤空值
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        String jsonInputString = objectMapper.writeValueAsString(request);
        System.out.println("请求参数: " + jsonInputString);
        
        // 发送请求
        try(OutputStream os = con.getOutputStream()) {
            byte[] input = jsonInputString.getBytes("utf-8");
            os.write(input, 0, input.length);
        }

        int responseCode = con.getResponseCode();
        // 读取响应
        if (responseCode == HttpURLConnection.HTTP_OK) {
            try(BufferedReader br = new BufferedReader(
                    new InputStreamReader(con.getInputStream(), "utf-8"))) {
                StringBuilder response = new StringBuilder();
                String responseLine = null;
                while ((responseLine = br.readLine()) != null) {
                    response.append(responseLine.trim());
                }
                return response.toString();
            }
        } else {
            // 读取错误响应
            try(BufferedReader br = new BufferedReader(
                    new InputStreamReader(con.getErrorStream(), "utf-8"))) {
                StringBuilder response = new StringBuilder();
                String responseLine = null;
                while ((responseLine = br.readLine()) != null) {
                    response.append(responseLine.trim());
                }
                System.err.println("错误响应: " + response.toString());
                return "{\"code\":" + responseCode + ",\"msg\":\"请求失败\"}";
            }
        }
    }

    public static void main(String[] args) {
        try {
            // 创建客户端实例
            DrugOutUploadApiClient client = new DrugOutUploadApiClient();

            // 创建出库数据列表
            List<DrugOutUploadApiClient.DrugOutItem> outDataList = new ArrayList<>();

            // 添加出库记录
            DrugOutUploadApiClient.DrugOutItem item = new DrugOutUploadApiClient.DrugOutItem();
            item.setYpwybsm("1021562371750417525"); // 药品唯一标识码
            item.setYppzwh("国药准字H20063830");
            item.setCrklx("10"); // 销售出库
            item.setCrksj("2025-09-14 11:11:25"); // 出库时间
            item.setScrq("2022-01-01"); // 生产日期
            item.setCpph("PH20220101"); // 产品批号
            item.setYxqz("2024-12-31"); // 有效期至
            item.setSl(10.0); // 药品数量
            item.setDj(25.5); // 医保支付价格
            item.setXsdj(25.5); // 药品销售价格
            item.setYpzsm("ZS20230001,ZS202300567657567657657657865765702"); // 药品追溯码
            item.setGmryzjlx("1"); // 购买人员证件类型 (1: 身份证)
            item.setGmryzjhm("340123199001011234"); // 购买人员证件号码
            item.setGmryxm("李四"); // 购买人员姓名
            item.setXsqd(1); // 销售渠道 (1: 线下)
            item.setBz("正常销售出库"); // 备注

            outDataList.add(item);

            // 添加第二条记录示例
            DrugOutUploadApiClient.DrugOutItem item2 = new DrugOutUploadApiClient.DrugOutItem();
            item2.setYpwybsm("1346857632788601987");
            item2.setYppzwh("国药准字H20210053");
            item2.setCrklx("13"); // 损耗出库
            item2.setCrksj("2025-09-14 11:11:25");
            item2.setScrq("2022-03-15");
            item2.setCpph("PH20220315");
            item2.setYxqz("2025-03-14");
            item2.setSl(2.0);
            item2.setDj(25.5); // 医保支付价格
            item2.setXsdj(25.5); // 药品销售价格
            item2.setYpzsm("ZS20230003,ZS20230004");
            item2.setGmryzjlx("1");
            item2.setGmryzjhm("340123199002021235");
            item2.setGmryxm("赵六");
            item2.setXsqd(1);
            item2.setBz("药品过期损耗");

            outDataList.add(item2);

            // 上传出库数据
            System.out.println("正在上传药品出库信息...");
            String result = client.uploadDrugOut(uscc, outDataList);

            // 输出结果
            System.out.println("药品出库信息上传结果: " + result);

        } catch (Exception e) {
            System.err.println("上传药品出库信息时发生错误: " + e.getMessage());
            e.printStackTrace();
        }
    }
}